﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Slb.Ocean.Petrel.DomainObject;
using Public.Ocean.Petrel.Extensions.Internal;

namespace Public.Ocean.Petrel.Extensions.DomainObject
{
    public static class CollectionExtensions
    {
        /// <summary>
        /// Gets all objects in the collection recursively.
        /// </summary>
        /// <param name="root">The root.</param>
        /// <param name="predicate">Match predicate.</param>
        /// <returns></returns>
        public static IEnumerable<object> GetAllRecursive(this Collection root, Func<object, bool> predicate)
        {
            return GetAllRecursive<object>(root, predicate);
        }

        /// <summary>
        /// Gets all objects in the collection recursively.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <returns></returns>
        public static IEnumerable<object> GetAllRecursive(this Collection root)
        {
            return GetAllRecursive<object>(root, obj => true);
        }

        /// <summary>
        /// Gets all objects in the collection recursively.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="root">The root.</param>
        /// <returns></returns>
        public static IEnumerable<TResult> GetAllRecursive<TResult>(this Collection root) where TResult : class
        {
            return GetAllRecursive<TResult>(root, obj => true);
        }

        /// <summary>
        /// Gets all objects in the collection recursively.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="root">The root.</param>
        /// <param name="predicate">The predicate.</param>
        /// <returns></returns>
        public static IEnumerable<TResult> GetAllRecursive<TResult>(this Collection root, Func<TResult, bool> predicate) where TResult : class
        {
            foreach (var collection in Enumerations.Flatten(new[] { root }, c => c.Collections))
            {
                foreach (var obj in collection)
                {
                    var typedObj = obj as TResult;
                    if (obj != null && predicate(typedObj))
                    {
                        yield return typedObj;
                    }
                }
            }
        }
    }
}
